package com.yifang.yibingproject.config.filter;

import com.alibaba.fastjson.JSONObject;
import com.yifang.yibingproject.utils.JwtUtils;
import com.yifang.yibingproject.utils.RedisUtils;
import com.yifang.yibingproject.utils.ResultUtils;
import com.yifang.yibingproject.utils.StringUtilOwn;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;

@Slf4j
@Component
public class JwtFilter extends OncePerRequestFilter {
    @Value("${yibin-project.token.expiration:12}")
    private Integer tokenExpiration;

    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        String tokenHeader = "Authorization";
        String token = httpServletRequest.getHeader(tokenHeader);
        if (StringUtilOwn.notEmpty(token)) {
            try {
                String userId = JwtUtils.getUserIdFromToken(token);
                String redisTokenKey = JwtUtils.getRedisTokenKey(userId);
                String redisToken = RedisUtils.getStr(redisTokenKey);
                log.info("redisToken=" + redisToken);
                String redisAuthKey = JwtUtils.getRedisAuthKey(userId);
                String redisAuth = RedisUtils.getStr(redisAuthKey);
                List<GrantedAuthority> authorityList = new ArrayList<>();
                if (StringUtilOwn.notEmpty(redisAuth)) {
                    String[] authArr = redisAuth.split(",");
                    for (String auth : authArr) {
                        if (!StringUtils.isEmpty(auth)) {
                            authorityList.add(new SimpleGrantedAuthority(auth));
                        }
                    }
                }

                // token auth续期
                RedisUtils.setStr(redisTokenKey, redisToken, Duration.ofHours(tokenExpiration));
                if (StringUtilOwn.notEmpty(redisAuth)) {
                    RedisUtils.setStr(redisAuthKey, redisAuth, Duration.ofHours(tokenExpiration));
                }

                UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userId, null, authorityList);
                authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));
                /*权限设置*/
                SecurityContextHolder.getContext().setAuthentication(authenticationToken);
                filterChain.doFilter(httpServletRequest, httpServletResponse);
            } catch (Exception e) {
                log.error("Token验证失败：" + e.getMessage(), e);
                // token验证失败
                httpServletResponse.setContentType("application/json;charset=utf-8");
                httpServletResponse.getWriter().write(JSONObject.toJSONString(ResultUtils.fail(-5, "Token错误或已过期，请重新登录")));
            }
        } else {
            filterChain.doFilter(httpServletRequest, httpServletResponse);
        }
    }
}
